花指令浅析
一次性进群,长期免费索取教程,没有付费教程。
教程列表见微信公众号底部菜单
进微信群回复公众号:微信群;QQ群:16004488
微信公众号:计算机与网络安全
ID:Computer-network
随着杀毒软件厂商与免杀之间对抗的升级,杀毒软件厂商推出了越来越多的成熟产品,一些传统的免杀方法正面临着越来越大的挑战,如果能够熟练运用花指令,就可以据此衍生出非常多的免杀方法及思路。
一、什么是花指令
花指令是源于汇编语言的一种技术,使用汇编语言的程序员为了避免他人将自己的思想“偷走”,或者是想要保护软件当中一个不为人知的小秘密,于是就采用了一些干扰指令来对自己的程序进行类似加密的操作。后来这种应用逐渐扩散开来了,也便有了它的一个专用名词“花指令”,意思就是如同花朵一样的指令,用它来吸引别人的注意力,而将真正的“果实”隐藏在后面。
简而言之,花指令就是一段本可以不存在的指令,它存在的唯一目的就是掩盖程序中的一些东西。例如编写木马程序时,间接地调用一些比较敏感的函数;向反汇编后的木马中加一个完全不需要的跳转,然后再跳回去;或在脚本木马中添加一个打印空字符的句子,嵌套一个空白的IF语句,等等。
如果一个程序中存在花指令,无非是出现以下两种情况:
当程序运行时会夹杂着运行花指令,这也是目前在免杀技术中应用最广也最常见的一种花指令添加方法,如图1所示。
图1 一般情况下的花指令应用逻辑
程序在运行时会因为花指令而改变原有的流程,这种情况多出现于高级语言中的花指令应用,而且并不常见。
花指令本是可以不存在的,也就是说,程序运行时这些指令完全是可以摒弃的(也可以将其称为垃圾代码),因此,我们可以将花指令定义为“程序正常运行时完全可以不需要的、人们刻意加进去的一段代码,或是刻意修改程序流程的一段代码”。大家只要知道花指令就是人们精心构造的一段垃圾代码,目的是起到类似加密作用的就行了。但是切记,不要将其与加密混淆。
二、脚本木马的花指令应用
鉴于脚本比较容易入门,而且了解脚本的朋友应该比汇编的要多一些,因此先以脚本木马的花指令为例来让大家对花指令有一个比较透彻的了解,以便于后面的学习。
先以一个最常见的DIY脚本木马为例来进行讲解,如果您对ASP脚本不熟悉也不要着急,目的主要是使您对花指令有一个大体的印象,知道要从哪里入手,在哪里更有利于添加花指令。
为了便于理解,在下面这个脚本木马的源代码中进行了简单的注释,如下所示:
上面的ASP脚本对于初学者来讲也许有一定的难度,其实大家不必细究每一句代码的意思,只需要了解一下程序的大体流程及作用即可。简单来说,上面的程序就是使在页面中输入的内容能够保存在目标服务器的某一个路径下。很显然这是一个具有典型木马性质的脚本,当然也会被杀毒软件查杀。下面就分析一下怎样在这个迷你木马脚本中添加花指令。
首先看前面的3行代码,很显然它们分别定义了一个变量,熟悉ASP脚本的朋友可能知道,ASP脚本是允许定义空变量的,所以完全可以在前面多定义几个毫无意义的空变量,例如:
而第五行代码是要将一个变量设置为FSO对象,完全可以将刚才定义的变量A1Pass设置为此对象,例如,<%Set A1pass=Server.CreateObject("Scripting.FileSystemObject")%>。
紧跟着的第六句代码是一个IF判断语句,自然也可以在其中嵌套一个IF子语句,例如:
这个IF子语句的意思是,如果1小于2则什么也不做,否则就打印字符“123456789”,其实还可以改用其他形式,大家可以自由发挥。在这个子语句中,如果将<%Response.write"123456789"%>写成<%Response.write""%>会发生什么情况呢?结果就是打印一个空的内容,等于没有这句代码,所以<%Response.write""%>在ASP脚本中几乎就是一个万能花指令,它可以随意插在脚本木马的任意位置。
这虽然是一个十分简单的例子,但是对于杀毒软件来说确实是有一些效果的,特别是对于卡巴斯基反病毒软件来说。从上面的例子我们能够学到些什么呢?相信除了学会脚本花指令的使用方法外,大家还会明白基本功是何等重要。就拿上面这个例子来说,想要熟练运用花指令,还要求您有一定的ASP语言功底。这里只是一个简单的ASP脚本木马,如果是PHP脚本木马又该怎么办呢?其实,除了所应用的语言不同外,思路上应该是基本一致的。
三、花指令的根基—汇编语言
既然花指令始于汇编,那么还是返回到汇编上来继续探讨吧,毕竟花指令对于我们来说更多的是应用在应用程序下。
想要学好花指令和一些在外行人看来很高超的免杀技术,就要对汇编的基本指令及其作用有一定的了解。当然,在此之前,还要摆脱对汇编的陌生感,不要一看到汇编指令就迷糊。
1、认识汇编
汇编语言和其他编程语言一样,也是一个大类(例如C对应的C++或C#等),这里主要学习汇编语言的常见格式,即OllyDbg默认设置下反汇编出来的格式(MASM格式)。我们最常用的计算机使用的都是Intel 80x86指令系统,而我们要了解的汇编语言也是基于Inter 80x86的。Intel 80x86指令系统大致可以分为以下5个功能组:
(1)数据传输指令
(2)逻辑运算指令
(3)串操作指令
(4)控制转移指令
(5)处理器控制指令
其中的第(1)、(2)、(4)类指令对免杀比较有用,当然这也是相对而言的。我们来看OllyDbg反汇编后的汇编指令格式,如表1所示。
从上面可以看出,OllyDbg的反汇编指令格式主要由4部分组成,其中“指令地址”表示该指令在内存中的虚拟地址,这个大家不用了解。“指令”也称为指令助记符,这就是汇编语言中的“代码”了。紧随其后的“目的操作数”与“源操作数”则代表操作的对象。最后的注释是对这一段指令的说明,可有可无,它在程序执行时不产生任何影响。
我们一起来看看程序被反汇编之后是什么样子的,如图2所示。可见在OllyDbg中主要分为“地址”、“HEX数据”、“反汇编”与“注释”这4个部分,其中的“反汇编”区域便是我们以后的主要“战场”。而“地址”代表程序加载到内存之后的虚拟地址,与定位特征码时的偏移量并不是一个概念,这点大家要注意。紧随其后的“HEX数据”表明这段指令在使用十六进制查看后的状态,而后面的“反汇编”就是指这段程序的反汇编代码了。另外,这里的“注释”大多是指程序中的字符或调用的命令,一般都是由OllyDbg自动生成的。
图2 OllyDbg生成的反汇编代码
下面简单为大家介绍一些比较常用的指令,这里的“比较常用的指令”是针对初级免杀技术而言的,这些指令并不用一次全部记下来,在以后遇到不懂的指令时就先到这里来查看它的用法,久而久之也就记熟了。
传送指令mov,示例:
进栈指令push,示例:
出栈指令pop,示例:
加法指令add,示例:
减法指令sub,示例:
增量指令inc,示例:
减量指令dec,示例:
无条件转移指令jmp,示例:
子程序调用指令call,示例:
虽然这些指令都是精挑细选出来的,但是可能仍有朋友在看完后还是一头雾水,其实没必要太较真,只要明白这些语句是怎么使用的就行了,暂时不用搞明白那些例句究竟是干什么的。
2、通过反汇编添加任意功能
学了这么多枯燥乏味的东西,究竟有什么作用呢?下面就来教大家利用现有的知识在一个应用程序中加上我们想要的功能。
下面的内容将会涉及上面介绍的“进栈指令push”、“无条件转移指令jmp”和“子程序调用指令call”,在介绍相关知识时会一边演示一边进行讲解。
首先确定目标,就是要为“木马辅助查找器”(以下简称“木马查找器”)加一个功能,使其在运行时向C盘下写入一个内容为C盘里文件目录结构的文本文档。
第一步运行OllyDbg,并打开“木马查找器”,找到一处“HEX数据”为0的区域,并记住开头的地址,如图3所示。
图3 找到空白区域
然后选中一片区域,并单击右键,选择“二进制”→“编辑”。在弹出的编辑对话框中输入要调用的命令cmd/c dir c:\>c:\lookme.txt,如图4所示。
图4 在0x004B1DB0处编辑调用命令
熟悉DOS命令的朋友应该知道,这条命令的作用就是将C盘根目录下的文件及目录信息写到c:\lookme.txt文件中。
再选中下面的隔一行处,并按空格键,这时会弹出一个汇编对话框,在此对话框中填写汇编指令push 0,如图5所示,然后记住这个地址。
图5 在0x004B1DD7处汇编指令
下面写入push开头地址,由图4可知,我们选择的开头地址为"004B1DB2",所以这条指令就应该为push 004B1DB2。在其后面写入call WinExec,最后在图6所示的地方找到整个程序的入口点,并写上最后一条汇编语句jmp 004B1D38,这样就可以完工了。
图6 跳转到入口点
接下来在OllyDbg的界面中单击右键,在弹出的菜单中依次选择“复制到可执行文件”→“所有更改”→“全部复制”,然后在弹出的窗口中再次单击右键,并选择“保存到文件”就行了。
最后就是修改入口点了,打开LordPE,将已经更改后的“木马查找器【改】.exe”拖放到LordPE的界面中。然后将程序的入口点改为"0x000B1DD7",也就是上图5所示的那个地址减去0x00400000所得到的数值,并单击“保存”,如图7所示。
图7 修改程序入口点
到这里,一个经我们亲手改造的程序就诞生了。通过上面的操作,我们赋予了程序原本没有的功能。不难发现,这次改造的中心思想就是使程序执行dir c:\>c:\lookme.txt这条系统命令。如果我们将其更换为其他命令又会如何呢?当然同样可以执行。这无形间就给了我们无限的发挥空间,至于其他利用,就留给您自己去实现吧。
但是现在有一个问题已经突显出来了,我们利用的原理究竟是什么呢?现在就为大家讲解。首先,我们利用了一个名为WinExec的系统API函数所执行的系统命令,它的定义如下:
由上可知,其调用方式为“WinExec(系统命令,0);”,但是汇编调用API函数遵循了sdtcall调用规则,也就是从右到左的压栈格式,所以在使用汇编实现时,要先将参数“0”压入栈,再将系统命令压入栈,然后才调用函数WinExec,最后则使用JMP跳转跳到程序原本的入口点,从而保证程序运行的顺序。其大致格式如下:
在保存完文件后,还要将这个文件的入口点改为push 0所在的地址,也就是例子中的0x00002100,以便使文件在运行时首先执行我们加入的这个功能。最后再由jmp 00001234跳到程序真正的入口点,使程序正常运行,前后连贯起来。
四、花指令入门
通过上面的学习,相信大家对汇编语言不再陌生,下面带着大家了解一下汇编语言中的花指令。其实花指令的原理就是运用一种保证堆栈平衡的思想,这与前面所介绍的基于脚本木马的花指令原理基本一样,最后都需要保证程序能够正常运行。
下面以“防杀精灵终极防杀代码”为例,来讲解一个花指令代码,如下所示:
由上面这段指令不难看出来,花指令确实是完全没有用的垃圾指令,它的存在只为了起到干扰的作用。其实我们在前面所讲的为应用程序增加功能的做法也是一种花指令的运用方法,大家看图8,很显然我们修改之后的程序已经成功地将PEID欺骗了。
图8 PEID被欺骗的效果
为了方便大家以后的学习,下面为大家举出一些常用的花指令组合:
开始部分所介绍的那个花指令,就是由上面成对的常用花指令组合而成的,而上面这些成对的花指令又是由一些基本的汇编语言构成的,所以说花指令的入门还是比较容易的。
我们只需要将上面的基本花指令简单地变通并组合一下,再添加一个跳转,改一下程序入口点就可成功地添加一个花指令。
但是除此之外,花指令的另一个作用就是干扰反汇编。但是在深入探讨干扰原理之前,我们先要更进一步地了解一下有关于汇编的相关知识。
之所以说汇编是一种最接近底层的语言,是因为汇编语言是完全可以和机械码一一对应的,我们先看看如下所示的一段反汇编指令。
以上反汇编代码的Hex dump部分就是能直接被CPU执行的机器码,而后面与之对应的Command部分就是OllyDbg根据这些机器码反汇编出来的汇编指令。在处理器与汇编领域,一般将这里的机器码称为OPCcode,例如我们现在看到的这些反汇编信息就是OllyDbg严格按照Intel的OPCode规则解析出来的。
现在来探讨一下如何干扰反汇编。我们都知道程序的执行离不开代码和数据,而怎样区分代码与数据一直以来都是反汇编领域的一个难题。目前主要有两种反汇编算法:一类是IDA使用的递归行进算法(Recursive traversal);另一类是OllyDbg、WinDbg等工具使用的线性扫描算法(Linear sweep)。
在这两种算法中,最容易被花指令所迷惑的就是线性扫描法。因为线性扫描法只是依次逐个地将整个模块的每一段OPCode都反汇编为汇编指令,但并没有对反汇编的内容做必要的判断,因此这种算法无法区分数据与代码的区别。换句话说,如果我们用使用线性扫描算法的反汇编引擎去试图对一个图片文件进行反汇编操作的话,那么它仍然会有模有样地给你生成很多汇编代码,虽然这全部都是错误的。
下面举一个例子。我们在某个C语言的项目中加入了如下代码:
然后用OllyDbg找到其所在位置,可以看到Olly Dbg生成的反汇编代码如下所示:
由此可见,OllyDbg的反汇编结果还是非常准确的,与我们在项目中的内联汇编完全相同。现在往C语言的项目中加入如下代码:
通过观察上面的代码我们发现,在中间多了一个数据定义的伪指令_EMIT。现在这部分代码的OllyDbg反汇编结果如下所示:
由以上反汇编代码可知,OllyDbg已经完全被我们欺骗了,因为它把我们定义的数据0xB8当成了代码去解释,从而造成了从此条指令开始,后面的所有指令都会被错误地解析一个字节,因此这会导致紧随其后的大片代码的反汇编错误。
在设计此类花指令的时候要注意,并不是所有的数据都会对其产生影响的,只有我们定义的数据恰好符合OPCode的规则,它才会被当成代码去解析。
微信公众号:计算机与网络安全
ID:Computer-network